﻿#include "facade.h"
#include "ui_facade.h"

Facade::Facade(QWidget *parent) :
    BaseFacade(parent),
    ui(new Ui::Facade)
{
    ui->setupUi(this);

    startUp();
}

Facade::~Facade()
{
    if(subscriber->isConnectedToHost())
        subscriber->disconnectFromHost();

    recvThread.quit();
    recvThread.wait();

    if(db.isOpen())
        db.close();

    delete ui;
}

void Facade::startUp()
{
    skin_def;

    note=nullptr;
    note2=nullptr;
    todo=nullptr;
    dbTry_failure=0;

    defPos.setX(d_width - DEF_WID);
    defPos.setY(200);
    moveDefPos();

    startSubscriber();
    startReceiver();

    if(!connectStorage())
        QMessageBox::warning(this,QStringLiteral("异常情况"),QStringLiteral("配置文件缺失！"));

    createMenu();
    fillUserInfo();
    login();
    detectTodo();

    createTray(QIcon(":/app.ico"));
    tray->setToolTip(QString::number(SP_VER) + QStringLiteral(" - 奇点助理运行中"));

    autoHide_timer=startTimer(AUTOHIDE_INTERVAL);
    connect(this,&TransFacade::trayStateChanged,this,&Facade::onTrayStateChanged);

    autoSync_timer=startTimer(AUTOSYNC_INTERVAL);
}

bool Facade::db_try()
{
    if(!db.isOpen())
        if(!db.open())
        {
            dbTry_failure += 1;
            return false;
        }
        else
            return true;
    else
        return true;
}

void Facade::login()
{
    if(!db_try())
        return;

    QSqlQuery query;
    query.prepare(QString("insert into %1 values (?,?,?,?)").arg(TD_LOGIN));
    query.addBindValue(QDateTime::currentDateTime());
    query.addBindValue(user.name);
    query.addBindValue(user.group);
    query.addBindValue(user.level);
    query.exec();
}

void Facade::fillUserInfo()
{
    if(user.name == USER_NAME_UKN)
    {
        QString name=QInputDialog::getText(this,QStringLiteral("请输入您的姓名"),QStringLiteral("姓名"));
        if(name.isEmpty())
            return;
        user.name=name;
        user.setName(name);
    }
}

void Facade::startReceiver()
{
    receiver=new BaseReceiver(0,false,PORT_GENERAL);
    connect(receiver,&BaseReceiver::received,this,&Facade::received);
    connect(&recvThread,&QThread::finished,receiver,&QObject::deleteLater);
    receiver->moveToThread(&recvThread);
    recvThread.start();
}

void Facade::startSubscriber()
{
    subscriber=new SimpleSubscriber;
    connect(subscriber,&SimpleSubscriber::received,
            this,&Facade::onMessageReceived);
    subscriber->wakeup();
}

void Facade::received(const QByteArray &data)
{
    QString request=data;
    if(request == R_CMD_RELOAD_MENU)
        reloadMenu();
}

void Facade::keyPressEvent(QKeyEvent *event)
{
    if(event->modifiers() == Qt::AltModifier && event->key()==Qt::Key_1)
        showNote();
    else if(event->modifiers() == Qt::AltModifier && event->key()==Qt::Key_2)
        showNote2();
    else if(event->modifiers() == Qt::AltModifier && event->key()==Qt::Key_E)
        showTodo();
    else
    {
        switch(event->key())
        {
        case Qt::Key_F3:
            invokeCalc();
            break;
        }
    }
}

void Facade::mouseDoubleClickEvent(QMouseEvent *)
{
    invokeTulingBox();
}

void Facade::timerEvent(QTimerEvent *event)
{
    int id=event->timerId();
    if(id == autoHide_timer)
    {
        if(!isActiveWindow() && isVisible())
            this->hide();
    }
    else if(id == autoSync_timer)
    {
        reloadMenu();
    }
}

void Facade::onTrayStateChanged()
{
    killTimer(autoHide_timer);
    autoHide_timer=startTimer(AUTOHIDE_INTERVAL);
}

void Facade::createMenu()
{
    menu=new QMenu(this);
    generateMenu();
}

void Facade::generateMenu()
{
    if(!db_try())
    {
        menu->addAction(QStringLiteral("退出"),QApplication::quit);
        return;
    }

    if(!menuItems.isEmpty())
        menuItems.clear();

    if(!menuList.isEmpty())
        menuList.clear();

    QSqlQuery query;
    query.exec(QString("select label,detail from %1 where category='%2'").arg(TD_MENU).arg("root"));
    while(query.next())
    {
        QString label=query.value(0).toString();
        QString detail=query.value(1).toString();
        if(label == "#")
            menu->addSeparator();
        else if(detail == "#menu")
        {
            QMenu *m_menu=menu->addMenu(label);
            menuList.append(m_menu);

            QSqlQuery query;
            query.exec(QString("select label,detail from %1 where category='%2'").arg(TD_MENU).arg(label));
            while(query.next())
            {
                QString label=query.value(0).toString();
                QString detail=query.value(1).toString();
                m_menu->addAction(label);
                menuItems.insert(label,detail);
            }
        }
        else
        {
            menu->addAction(label);
            menuItems.insert(label,detail);
        }
    }
    menu->addSeparator();
    createPropsMenu();
    createUserMenu();
    createOptionMenu();
    menu->addSeparator();
    createFavoriteMenu();
    connect(menu,&QMenu::triggered,this,&Facade::processMenuAction);
}

void Facade::createUserMenu()
{
    QMenu *m_user=menu->addMenu(QStringLiteral("用户"));
    m_user->addAction(QStringLiteral("设置名称"),this,&Facade::setUerName);
    m_user->addAction(QStringLiteral("设置组别"),this,&Facade::setUserGroup);
}

void Facade::reloadMenu()
{
    menu->clear();
    menu->disconnect();
    generateMenu();
}

void Facade::reloadMenuAction()
{
    reloadMenu();
    tray->showMessage(QStringLiteral("消息"),QStringLiteral("菜单已刷新"));
}

void Facade::setUerName()
{
    QString name=QInputDialog::getText(this,QStringLiteral("请输入您的姓名"),QStringLiteral("姓名："));
    if(name.isEmpty())
        return;
    if(user.name == name)
        return;
    user.name = name;
    user.setName(name);
}

void Facade::setUserGroup()
{
    QString group=QInputDialog::getText(this,QStringLiteral("请输入要加入的组别"),QStringLiteral("组别："));
    if(group.isEmpty())
        return;
    if(user.group == group)
        return;
    user.group=group;
    user.setGroup(group);
}

void Facade::onMessageReceived(const QMQTT::Message &message)
{
    Pie pie(message.payload());
    if(!pie.isEmpty())
    {
        if(pie.contain("label") && pie.contain("detail"))
        {
            pop(pie.get("label"),pie.get("detail"));
        }
    }
}

void Facade::pop(const QString &label, const QString &detail)
{
    if(popup == nullptr)
        popup=new Popup(this);
    popup->showMe(label,detail);
}

void Facade::createOptionMenu()
{
    QMenu *m_option=menu->addMenu(QStringLiteral("选项"));
    m_option->addAction(QStringLiteral("本机信息"),::sp_aboutDevice);
    m_option->addAction(QStringLiteral("应用信息"),::sp_aboutApp);
    m_option->addAction(QStringLiteral("版本信息"),this,&Facade::aboutVersion);
    m_option->addAction(QStringLiteral("硬件信息"),this,&Facade::showHardwareInfo);
    m_option->addSeparator();
    m_option->addAction(QStringLiteral("刷新菜单"),this,&Facade::reloadMenuAction);
    m_option->addAction(QStringLiteral("设置开机启动"),this,&Facade::setStartup);
    m_option->addAction(QStringLiteral("取消开机启动"),this,&Facade::unsetStartup);
    m_option->addSeparator();
    m_option->addAction(QStringLiteral("退出"),QApplication::quit);
}

void Facade::setStartup()
{
    ::sp_setStartup(true);
}

void Facade::unsetStartup()
{
    ::sp_setStartup(false);
}

void Facade::createPropsMenu()
{
    QMenu *m_props=menu->addMenu(QStringLiteral("组件"));

    QMenu *m_note=m_props->addMenu(QStringLiteral("速记"));
    m_note->addAction(QStringLiteral("速记1 (Alt+1)"),this,&Facade::showNote);
    m_note->addAction(QStringLiteral("速记2 (Alt+2)"),this,&Facade::showNote2);
    m_props->addAction(QStringLiteral("待办事项 (Alt+E)"),this,&Facade::showTodo);
    m_props->addAction(QStringLiteral("计算器 (F3)"),this,&Facade::invokeCalc);
    m_props->addAction(QStringLiteral("AI助理 (双击)"),this,&Facade::invokeTulingBox);
}

void Facade::createFavoriteMenu()
{
    m_favorite=menu->addMenu(QStringLiteral("收藏夹"));
    createFavoriteMenuItem();
}

void Facade::createFavoriteMenuItem()
{
    if(!bookmarks.isEmpty())
        bookmarks.clear();

    QSqlQuery query;
    QString sql=QString("select category from %1 GROUP BY category").arg(TD_BOOKMARKS);
    query.exec(sql);

    while(query.next())
    {
        QString category=query.value("category").toString();
        QMenu *m_category=m_favorite->addMenu(category);
        QSqlQuery query;
        QString sql=QString("select label,detail from %1 where category='%2'").arg(TD_BOOKMARKS).arg(category);
        query.exec(sql);

        while (query.next()) {
            QString label=query.value("label").toString();
            QString detail=query.value("detail").toString();
            bookmarks.insert(label,detail);
            m_category->addAction(label);
        }
    }
    connect(m_favorite,&QMenu::triggered,this,&Facade::processFavoriteAction);
}

void Facade::reloadFavoriteMenu()
{
    m_favorite->clear();
    m_favorite->disconnect();
    createFavoriteMenuItem();
}

void Facade::processFavoriteAction(QAction *action)
{
    bookmarks.open(action->text());
}

void Facade::processMenuAction(QAction *action)
{
    QString label=action->text();
    if(!menuItems.contains(label))
        return;

    QString detail=menuItems.value(label);
    if(!detail.contains(" "))
        QDesktopServices::openUrl(QUrl(detail));
    else
        QProcess::startDetached(detail);
}

void Facade::aboutVersion()
{
    QString info=QStringLiteral("附加信息：\n");
    ::sp_aboutVersionAddition(info);
}

void Facade::showHardwareInfo()
{
    QString info=QStringLiteral("CPU：\n") + ::reg_getCPUName() + "\n"
            + QStringLiteral("主板：\n") + ::reg_getBIOSInfo();
    QMessageBox::information(0,QStringLiteral("硬件信息"), info);
}

void Facade::showNote()
{
    if(note==nullptr)
        note=new Note(this,userLand);

    note->load();
    note->move(300,100);
    note->show();
}

void Facade::showNote2()
{
    if(note2==nullptr)
        note2=new Note2(this,userLand);

    note2->load();
    note2->move(400,200);
    note2->show();
}

void Facade::showTodo()
{
    if(todo==nullptr)
        todo=new Todo(this,userLand);

    todo->load();
    todo->move(200,100);
    todo->show();
}

void Facade::detectTodo()
{
    if(todo==nullptr)
        todo=new Todo(this,userLand);

    todo->move(200,100);
    todo->detect();
}

void Facade::invokeCalc()
{
    QDesktopServices::openUrl(QUrl(Calc));
}

void Facade::invokeTulingBox()
{
    if(QFile::exists(TulingBox))
        QDesktopServices::openUrl(QUrl(TulingBox));
}

bool Facade::connectStorage()
{
    if(!QFile::exists(DB_CONFIG))
        return false;

    db=sp_createStorage(DB_CONFIG);
    return true;
}
